package com.kexio.auth.filter;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.kexio.auth.context.TenantContextHolder;
import com.kexio.auth.tenant.TenantResolver;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * 租户Web过滤器
 * 
 * 负责在Web请求生命周期中管理租户上下文：
 * 1. 请求开始时：从HTTP请求中解析租户ID并设置到ThreadLocal
 * 2. 请求处理中：确保租户上下文在整个请求链中可用
 * 3. 请求结束时：清理ThreadLocal，防止内存泄漏
 * 4. 异常处理：确保即使发生异常也能正确清理资源
 * 
 * 过滤器特性：
 * - 高优先级执行：在认证过滤器之前执行，确保认证时已有租户上下文
 * - 异常安全：使用try-finally确保ThreadLocal总是被清理
 * - 性能优化：缓存解析结果，避免重复计算
 * - 可观察性：集成日志MDC，支持分布式链路追踪
 * - 可配置：支持跳过特定路径，提高性能
 * 
 * 执行顺序：
 * 1. TenantWebFilter (Order = 10) - 设置租户上下文
 * 2. JwtAuthenticationFilter (Order = 20) - JWT认证
 * 3. 业务过滤器和控制器
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Component
@Order(10) // 高优先级，确保在JWT过滤器之前执行
@ConditionalOnProperty(prefix = "kexio.auth.tenant", name = "enabled", havingValue = "true", matchIfMissing = false)
public class TenantWebFilter implements Filter {
    
    private static final Logger logger = LoggerFactory.getLogger(TenantWebFilter.class);
    
    // ==================== 配置常量 ====================
    
    /**
     * MDC中租户ID的键名
     */
    private static final String MDC_TENANT_KEY = "tenantId";
    
    /**
     * 请求属性中存储租户解析时间的键名
     */
    private static final String RESOLVE_TIME_ATTRIBUTE = "_tenant_resolve_time";
    
    /**
     * 需要跳过租户解析的路径前缀
     */
    private static final String[] SKIP_PATHS = {
        "/actuator/",
        "/health",
        "/favicon.ico",
        "/robots.txt",
        "/static/",
        "/public/",
        "/webjars/",
        "/swagger-ui/",
        "/v3/api-docs/",
        "/error"
    };
    
    // ==================== 依赖注入 ====================
    
    @Autowired
    private TenantResolver tenantResolver;
    
    // ==================== 过滤器生命周期 ====================
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("租户Web过滤器初始化完成");
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        // 1. 检查是否需要跳过租户解析
        if (shouldSkipTenantResolution(httpRequest)) {
            logger.trace("跳过租户解析: {}", httpRequest.getRequestURI());
            chain.doFilter(request, response);
            return;
        }
        
        // 2. 执行租户上下文管理
        processTenantContext(httpRequest, httpResponse, chain);
    }
    
    @Override
    public void destroy() {
        logger.info("租户Web过滤器销毁");
    }
    
    // ==================== 核心处理逻辑 ====================
    
    /**
     * 处理租户上下文的核心逻辑
     */
    private void processTenantContext(HttpServletRequest request, HttpServletResponse response, 
                                     FilterChain chain) throws IOException, ServletException {
        
        String tenantId = null;
        long startTime = System.currentTimeMillis();
        
        try {
            // 1. 解析租户ID
            tenantId = resolveTenantId(request);
            
            // 2. 设置租户上下文
            if (StringUtils.hasText(tenantId)) {
                TenantContextHolder.setTenant(tenantId);
                setMDCTenantInfo(tenantId);
                
                logger.debug("租户上下文已设置: {} (请求: {} {})", 
                    tenantId, request.getMethod(), request.getRequestURI());
            } else {
                logger.trace("未解析到租户ID，使用默认租户: {} (请求: {} {})", 
                    TenantContextHolder.getTenant(), request.getMethod(), request.getRequestURI());
            }
            
            // 3. 记录解析时间
            recordResolveTime(request, startTime);
            
            // 4. 继续过滤器链
            chain.doFilter(request, response);
            
        } catch (Exception e) {
            logger.error("租户上下文处理发生异常: {} (租户: {}, 请求: {} {})", 
                e.getMessage(), tenantId, request.getMethod(), request.getRequestURI(), e);
            throw e;
        } finally {
            // 5. 清理租户上下文（确保总是执行）
            cleanupTenantContext(tenantId, startTime);
        }
    }
    
    /**
     * 解析租户ID
     */
    private String resolveTenantId(HttpServletRequest request) {
        try {
            return tenantResolver.resolve(request);
        } catch (Exception e) {
            logger.warn("租户解析失败，使用默认租户: {} (请求: {} {})", 
                e.getMessage(), request.getMethod(), request.getRequestURI());
            return tenantResolver.getDefaultTenantId();
        }
    }
    
    /**
     * 设置MDC租户信息
     */
    private void setMDCTenantInfo(String tenantId) {
        try {
            MDC.put(MDC_TENANT_KEY, tenantId);
        } catch (Exception e) {
            logger.debug("设置MDC租户信息失败: {}", e.getMessage());
        }
    }
    
    /**
     * 记录租户解析时间
     */
    private void recordResolveTime(HttpServletRequest request, long startTime) {
        long resolveTime = System.currentTimeMillis() - startTime;
        request.setAttribute(RESOLVE_TIME_ATTRIBUTE, resolveTime);
        
        if (resolveTime > 100) { // 超过100ms记录警告
            logger.warn("租户解析耗时过长: {}ms (请求: {} {})", 
                resolveTime, request.getMethod(), request.getRequestURI());
        } else if (logger.isTraceEnabled()) {
            logger.trace("租户解析耗时: {}ms", resolveTime);
        }
    }
    
    /**
     * 清理租户上下文
     */
    private void cleanupTenantContext(String tenantId, long startTime) {
        try {
            // 1. 清理租户上下文
            TenantContextHolder.clear();
            
            // 2. 清理MDC
            MDC.remove(MDC_TENANT_KEY);
            
            // 3. 记录处理总时间
            long totalTime = System.currentTimeMillis() - startTime;
            
            if (logger.isDebugEnabled()) {
                logger.debug("租户上下文已清理: {} (总耗时: {}ms)", tenantId, totalTime);
            }
            
        } catch (Exception e) {
            logger.error("清理租户上下文时发生异常: {}", e.getMessage(), e);
            // 确保ThreadLocal被清理，即使发生异常
            try {
                TenantContextHolder.clear();
                MDC.remove(MDC_TENANT_KEY);
            } catch (Exception cleanupException) {
                logger.error("强制清理租户上下文失败: {}", cleanupException.getMessage());
            }
        }
    }
    
    // ==================== 辅助方法 ====================
    
    /**
     * 检查是否应该跳过租户解析
     */
    private boolean shouldSkipTenantResolution(HttpServletRequest request) {
        String path = request.getRequestURI();
        
        // 检查静态资源和健康检查路径
        for (String skipPath : SKIP_PATHS) {
            if (path.startsWith(skipPath)) {
                return true;
            }
        }
        
        // 检查OPTIONS请求（预检请求）
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            return true;
        }
        
        return false;
    }
    
    /**
     * 获取请求的租户解析时间
     */
    public static Long getResolveTime(HttpServletRequest request) {
        Object resolveTime = request.getAttribute(RESOLVE_TIME_ATTRIBUTE);
        return resolveTime instanceof Long ? (Long) resolveTime : null;
    }
    
    /**
     * 获取支持的跳过路径列表
     */
    public String[] getSkipPaths() {
        return SKIP_PATHS.clone();
    }
    
    // ==================== 管理和监控方法 ====================
    
    /**
     * 获取过滤器统计信息
     */
    public FilterStatistics getStatistics() {
        return new FilterStatistics();
    }
    
    /**
     * 过滤器统计信息
     */
    public static class FilterStatistics {
        private final String filterName = "TenantWebFilter";
        private final int order = 10;
        private final String[] skipPaths = SKIP_PATHS.clone();
        
        public String getFilterName() {
            return filterName;
        }
        
        public int getOrder() {
            return order;
        }
        
        public String[] getSkipPaths() {
            return skipPaths.clone();
        }
        
        public String getStatus() {
            return "ACTIVE";
        }
        
        public String getDescription() {
            return "租户Web过滤器 - 管理请求级租户上下文";
        }
        
        @Override
        public String toString() {
            return String.format("FilterStatistics{name='%s', order=%d, skipPaths=%d, status='%s'}", 
                filterName, order, skipPaths.length, getStatus());
        }
    }
}
